package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.base.exception.Assert;
import com.atguigu.srb.base.exception.SrbBussinessException;
import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.utils.IpUtils;
import com.atguigu.srb.base.utils.JwtUtils;
import com.atguigu.srb.common.utils.MD5;
import com.atguigu.srb.common.utils.RegexValidateUtils;
import com.atguigu.srb.core.pojo.entity.UserAccount;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.UserLoginRecord;
import com.atguigu.srb.core.pojo.vo.UserInfoSearchVO;
import com.atguigu.srb.core.pojo.vo.UserInfoVO;
import com.atguigu.srb.core.pojo.vo.UserResponseVO;
import com.atguigu.srb.core.service.UserAccountService;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.core.service.UserLoginRecordService;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;

/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-01-04
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    UserAccountService userAccountService;
    @Resource
    UserLoginRecordService userLoginRecordService;
    @Resource
    StringRedisTemplate stringRedisTemplate; //必须和sms服务 存验证码的模板类一样
    @Override
    public void register(UserInfoVO userInfo) {
        //1、验证参数
        String code = userInfo.getCode();
        String mobile = userInfo.getMobile();
        String password = userInfo.getPassword();
        Integer userType = userInfo.getUserType();
        Assert.assertTrue(StringUtils.isEmpty(code),ResponseEnum.CODE_ERROR);
        Assert.assertTrue(StringUtils.isEmpty(mobile)||!RegexValidateUtils.checkCellphone(mobile),
                ResponseEnum.MOBILE_ERROR);
        Assert.assertTrue(StringUtils.isEmpty(password),ResponseEnum.PASSWORD_NULL_ERROR);
        Assert.assertTrue(userType==null,ResponseEnum.USER_TYPE_ERROR);
        //2、验证验证码
        //从redis中获取手机号码的注册验证码 和本次提交的进行比较
        String redisCode = stringRedisTemplate.opsForValue().get("sms:code:" + mobile);
        Assert.assertTrue(redisCode==null || !StringUtils.equals(redisCode,code),
                    ResponseEnum.CODE_ERROR);
        //3、重复注册验证
        //使用注册手机号码到数据库中判断是否已被使用
        int count = this.count(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, mobile));
        Assert.assertTrue(count>0,
                ResponseEnum.MOBILE_EXIST_ERROR);
        //4、密码加密
        //MD5方式加密 相同的明文每次加密的密文是一样的，所以MD5加密可以被暴力破解
        //加盐：   前端提交的明文 加密  + 后端提供的盐 再次进行加密 得到密文字符串
        //        数据库被暴力破解时， 得到的是 明文加密结果+盐的 明文
        // 一个用户对应一个盐 也可以提高破解难度
        String salt = UUID.randomUUID().toString().substring(0,6);
        String encodePwd = MD5.encrypt(MD5.encrypt(password)+salt);
        //5、保存数据到数据库
        UserInfo user = new UserInfo();
        user.setUserType(userType);
        user.setMobile(mobile);
        user.setPassword(encodePwd);
        user.setNickName("谷粉_"+ UUID.randomUUID().toString().substring(0,6));
        user.setHeadImg("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        user.setIntegral(0);
        user.setStatus(1);
        user.setSalt(salt);
        this.save(user);
        //删除已使用的验证码
        stringRedisTemplate.delete("sms:code:" + mobile);

        //6、初始化注册用户的账户数据
        UserAccount userAccount = new UserAccount();
        userAccount.setUserId(user.getId());
        userAccount.setAmount(new BigDecimal(0));
        userAccount.setFreezeAmount(new BigDecimal(0));
        userAccountService.save(userAccount);
    }

    @Override
    public UserResponseVO login(UserInfoVO userInfoVO, HttpServletRequest request) {
        //1、验证参数
        String mobile = userInfoVO.getMobile();
        String password = userInfoVO.getPassword();
        Integer userType = userInfoVO.getUserType();
        Assert.assertTrue(StringUtils.isEmpty(mobile)||!RegexValidateUtils.checkCellphone(mobile),
                ResponseEnum.MOBILE_ERROR);
        Assert.assertTrue(StringUtils.isEmpty(password),ResponseEnum.PASSWORD_NULL_ERROR);
        Assert.assertTrue(userType==null,ResponseEnum.USER_TYPE_ERROR);
        //2、登录
        //2.1 使用mobile+userType查询数据：判断账号是否正确
        UserInfo userInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getMobile, mobile)
                .eq(UserInfo::getUserType, userType));
        Assert.assertTrue(userInfo==null,ResponseEnum.LOGIN_MOBILE_ERROR);
        //2.2 再对用户登录的明文密码加密 和数据库查询的用户密码比较 判断密码是否正确
        String encodePwd = MD5.encrypt(MD5.encrypt(password)+userInfo.getSalt());
        Assert.assertTrue(!encodePwd.equals(userInfo.getPassword()),ResponseEnum.LOGIN_PASSWORD_ERROR);
        //3、封装响应对象
        UserResponseVO userResponseVO = new UserResponseVO();
        userResponseVO.setHeadImg(userInfo.getHeadImg());
        userResponseVO.setNickName(userInfo.getNickName());
        userResponseVO.setUserType(userInfo.getUserType());
        //jwt token载荷的值不能为null
        String token = JwtUtils.createToken(userInfo.getId(), userInfo.getNickName());
        userResponseVO.setToken(token);


        //保存用户的登录日志
        UserLoginRecord userLoginRecord = new UserLoginRecord();
        userLoginRecord.setIp(IpUtils.getIpAddressAtService(request));
        userLoginRecord.setUserId(userInfo.getId());
        userLoginRecord.setCreateTime(new Date());
        userLoginRecord.setUpdateTime(new Date());
        userLoginRecordService.save(userLoginRecord);

        return userResponseVO;
    }

    @Override
    public Page<UserInfo> listPage(UserInfoSearchVO userInfoSearchVO, Integer pageNum, Integer pageSize) {
        Page<UserInfo> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<UserInfo> queryWrapper = Wrappers.lambdaQuery(UserInfo.class);
        String mobile = userInfoSearchVO.getMobile();
        Integer status = userInfoSearchVO.getStatus();
        Integer userType = userInfoSearchVO.getUserType();
        //设置条件到queryWrapper中生成sql
        if(!StringUtils.isEmpty(mobile)){//手机号模糊查询
            queryWrapper.like(UserInfo::getMobile , mobile);
        }
        if(status!=null){
            queryWrapper.eq(UserInfo::getStatus,status);
        }
        if(userType!=null){
            queryWrapper.eq(UserInfo::getUserType,userType);
        }
        this.page(page,queryWrapper);
        return page;
    }
}
